﻿using FAP.Cores.CaptchaCenter;
using FAP.Cores.Threading;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FAP.DataAccess;
using FAP.Cores.Task;
using FAP.DataAccess.BLL;
using System.Web;
using log4net;

namespace FAP.Cores.Task
{
    public class FapWork : FapTask
    {
        private ILog m_log = LogManager.GetLogger(typeof(FapWork));
        public delegate void FinishStep(FapWork task);
        public FinishStep OnFinishStep = null;
        private int currentStep = 0;
        private chitietnghiepvu ctnv;

        public chitietnghiepvu ChiTietNghiepVu
        {
            get { return ctnv; }
        }
        private taikhoan tk = new taikhoan();
        public Requesting.Requester requester = new Requesting.Requester();
        private CaptchaDTO m_capcha;
        public System.Net.WebResponse response;
        private FapWork() { }

        public string LastHTML = "";
        private string str_DataPost;

        public string DataPost
        {
            get { return str_DataPost; }
        }


        public FapWork(chitietnghiepvu ct)
        {
            this.ctnv = ct;
            if (ct == null)
                throw new Exception("FapWork(chitietnghiepvu ct) not implement");
        }
        private string key_mabaiviet = "_mabaiviet_";
        private string key_topicid = "_topicid_";
        public override object RunIt()
        {
            tk = GetAccount();
            if (tk == null)
                tk = new taikhoan();
            //var lstBuocThucHien = ctnv.buocthuchiens.OrderBy(m => m.thutu).ToList();
            var lstBuocThucHien = buocthuchien.buocthuchienSelectRowByForeignKey_chitietnghiepvuid(ctnv.id)
                .OrderBy(m => m.thutu).ToList();
            if (lstBuocThucHien.Count == 0)
            {
                throw new Exception("BuocThucHiens is empty");
            }
            //var lstFieldFormat = fieldformat.fieldformatSelectAll();
            for (int i = currentStep; i < lstBuocThucHien.Count; i++)
            {
                buocthuchien step = lstBuocThucHien[i];
                var lstCTBTH = chitietbuocthuchien.chitietbuocthuchienSelectRowByForeignKey_idbuocthuchien(step.id);
                if ((lstCTBTH == null || lstCTBTH.Count == 0) && step.method.ToLower() == "post")
                {
                    throw new Exception("ChiTietBuocThucHiens of method POST is empty from step " + (i + 1).ToString());
                }
                string link = step.link;
                if (link == null || link == "")
                {
                    throw new Exception("Link is null");
                }
                if (link.IndexOf(key_mabaiviet) > -1)
                {
                    string strMaBaiViet = this.GetMaBaiViet();
                    if (string.IsNullOrEmpty(strMaBaiViet))
                    {
                        throw new Exception("GetMaBaiViet() not override");
                    }
                    else
                    {
                        link = link.Replace(key_mabaiviet, this.GetMaBaiViet());
                    }
                }
                if (link.IndexOf(key_topicid) > -1)
                {
                    string strTopicId = this.GetTopicId();
                    if (string.IsNullOrEmpty(strTopicId))
                    {
                        throw new Exception("GetTopicId() not override");
                    }
                    else
                    {
                        link = link.Replace(key_topicid, this.GetTopicId());
                    }
                }
                string data = "cookieuser=1&cookie=0";
                //string data = "";
                if (step.method.ToLower() == "get")
                {
                    m_log.Info("Before Get: " + link);
                    var response = requester.GetData(link, false, tk.cookie);
                    if (response == null)
                    {
                        continue;
                        throw new Exception("Can not getting data from " + link);
                    }
                    else
                    {
                        m_log.Info("Get: " + link);
                        LastHTML = requester.GetHtmlFromResponse(response);
                    }
                }
                else
                {
                    if (m_capcha == null)
                    {
                        var capchaStepDetail = lstCTBTH.Where(m => m.fieldformatid == 13).SingleOrDefault();
                        var capchaStepHuman = lstCTBTH.Where(m => m.fieldformatid == 9).SingleOrDefault();
                        
                        CaptchaDTO capcha = new CaptchaDTO();
                        if (capchaStepDetail != null)
                        {
                            capcha.html = LastHTML;
                            capcha.xpath = capchaStepDetail.dulieumacdinh;
                            capcha.fieldNameVerifyCaptcha = capchaStepDetail.tenfield;
                            if (capchaStepHuman == null && string.IsNullOrEmpty(capchaStepHuman.tenfield))
                            {
                                capcha.fieldNameVerifyCaptcha = "@";
                            }
                            else
                            {
                                capcha.fieldNameVerifyCaptcha = capchaStepHuman.tenfield;
                            }
                            _strCapchaValueFieldName = capchaStepDetail.tenfield;
                            CaptchaTask capchaTask = new CaptchaTask(capcha);
                            capchaTask.TimeToRepeat = 0;
                            capchaTask.onFinished += onFinishedCapcha;
                            capchaTask.onError += onErrorCapcha;
                            //capchaTask.RunIt();
                            FAP.Cores.Threading.ThreadControl.AddTasks(capchaTask);
                            m_log.Info("Geting captcha");
                            currentStep = i;
                            this.WaitCaptcha();
                            return null;
                        }
                    }
                    foreach (var stepDetail in lstCTBTH)
                    {
                        
                        //string strTemp = stepDetail.fieldformat.ten.ToLower();
                        string strNameFieldformat = fieldformat.fieldformatSelectRow(stepDetail.fieldformatid).ten;
                        switch (strNameFieldformat.ToLower())
                        {
                            case "username":
                                string strUserName = this.tk.tendangnhap;
                                if (string.IsNullOrEmpty(strUserName))
                                {
                                    throw new Exception("Missing UserName, use GetAccount(taikhoan tk)");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, strUserName);
                                break;
                            case "password":
                                string strPassword = this.tk.matkhau;
                                if (string.IsNullOrEmpty(strPassword))
                                {
                                    throw new Exception("Missing Password, use GetAccount(taikhoan tk)");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, strPassword);
                                break;
                            case "email":
                                //this._strEmailFieldName = stepDetail.tenfield;
                                string strEmail = this.tk.email;
                                if (string.IsNullOrEmpty(strEmail))
                                {
                                    throw new Exception("Missing Email field");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, strEmail);
                                break;
                            case "notsend":
                                data += string.Format("&{0}={1}", stepDetail.tenfield, "");
                                break;
                            case "default":
                                data += string.Format("&{0}={1}", stepDetail.tenfield, stepDetail.dulieumacdinh);
                                break;
                            case "humanverify":
                                this._strHumanverifyFieldName = stepDetail.tenfield;
                                string strHumanverify = this.GetHumanverify();
                                if (strHumanverify == null)
                                {
                                    throw new Exception("Missing Humanverify field");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, strHumanverify);
                                break;
                            case "token":
                                this._strTokenFieldName = stepDetail.tenfield;
                                string strToken = this.GetToken();
                                if (string.IsNullOrEmpty(strToken))
                                {
                                    throw new Exception("Missing Token field");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, strToken);
                                break;
                            case "title":
                                this._strTitleFieldName = stepDetail.tenfield;
                                string strTitle = this.GetTitle();
                                if (string.IsNullOrEmpty(strTitle))
                                {
                                    throw new Exception("Missing Title field");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, strTitle);
                                break;
                            case "content":
                                this._strContentFieldName = stepDetail.tenfield;
                                string strContent = this.GetContent();
                                if (string.IsNullOrEmpty(strContent))
                                {
                                    throw new Exception("Missing Content field");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, strContent);
                                break;
                            case "contentbbcode":
                                this._strContentFieldName = stepDetail.tenfield;
                                string strContentBBCode = this.GetContentBBCode();
                                if (string.IsNullOrEmpty(strContentBBCode))
                                {
                                    throw new Exception("Missing ContentBBCode field");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, strContentBBCode);
                                break;
                            case "bb_userid":
                                this._strBBUseridFieldName = stepDetail.tenfield;
                                string strBBUserid = this.GetBBUserid();
                                if (string.IsNullOrEmpty(strBBUserid))
                                {
                                    throw new Exception("Missing bb_userid field");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, strBBUserid);
                                break;
                            case "capchavalue":
                                this._strCapchaValueFieldName = stepDetail.tenfield;
                                data += string.Format("&{0}={1}", stepDetail.tenfield, m_capcha.captcha);
                                break;
                            case "mabaiviet":
                                string strMaBaiViet = this.GetMaBaiViet();
                                if (string.IsNullOrEmpty(strMaBaiViet))
                                {
                                    throw new Exception("GetMaBaiViet() not override");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, this.GetMaBaiViet());
                                break;
                            case "topicid":
                                string strTopicId = this.GetTopicId();
                                if (string.IsNullOrEmpty(strTopicId))
                                {
                                    throw new Exception("GetTopicId() not override");
                                }
                                data += string.Format("&{0}={1}", stepDetail.tenfield, this.GetTopicId());
                                break;
                            case "runtime":
                                string strRunTimeFieldName = stepDetail.tenfield;
                                string strValue = FAP.Utility.HtmlHelper.GetValueByName(LastHTML, strRunTimeFieldName);
                                if (string.IsNullOrEmpty(strValue))
                                {
                                    throw new Exception(string.Format("Can't value of {0} find in HTML", stepDetail.tenfield));
                                }
                                data += string.Format("&{0}={1}", strRunTimeFieldName, strValue);
                                break;
                        }
                    }

                    if (data != "" && link != "")
                    {
                        this.str_DataPost = data;
                        data = data.Replace("\0", "");
                        m_log.Info("Before Post: " + link);
                        response = requester.PostData(link, data, false, tk.cookie);
                        if (response == null)
                        {
                            continue;
                            //throw new Exception("Response return NULL from PostData() function.");
                        }
                        m_log.Info("Post: " + link);
                        LastHTML = requester.GetHtmlFromResponse(response);
                    }
                    if (OnFinishStep != null)
                    {
                        OnFinishStep(this);
                    }
                }
            }
            return base.RunIt();
        }

        #region events
        public void onFinishedCapcha(object sender, object result)
        {
            if (result == null)
                return;
            CaptchaDTO c = (CaptchaDTO)result;
            this.m_capcha = c;
            //this.RunIt();
            FAP.Cores.Threading.ThreadControl.AddTasks(this);

        }

        public static void onErrorCapcha(object sender, object result)
        {
            //m_log.Error(result);
            throw new Exception("Capcha not avilable");
        }
        #endregion

        #region BB_Userid
        private string _strBBUseridFieldName;
        public string BBUseridFieldName
        {
            get { return _strBBUseridFieldName; }
        }
        public virtual string GetBBUserid()
        {
            return null;
        }
        #endregion

        #region Capcha
        private string _strCapchaValueFieldName;

        public string CapchaValue
        {
            get { return _strCapchaValueFieldName; }
        }
        private string GetCapchaValue()
        {
            return null;
        }
        #endregion

        #region Content
        private string _strContentFieldName;

        public string ContentFieldName
        {
            get { return _strContentFieldName; }
        }
        public virtual string GetContent()
        {
            return null;
        }
        #endregion

        #region Content BBCode
        public virtual string GetContentBBCode()
        {
            return null;
        }
        #endregion

        #region Title
        private string _strTitleFieldName;

        public string TitleFieldName
        {
            get { return _strTitleFieldName; }
        }
        public virtual string GetTitle()
        {
            return null;
        }
        #endregion

        #region Token
        private string _strTokenFieldName;

        public string TokenFieldName
        {
            get { return _strTokenFieldName; }
        }
        public virtual string GetToken()
        {
            return null;
        }
        #endregion

        #region Humanverify
        private string _strHumanverifyFieldName;

        public string HumanverifyFieldName
        {
            get { return _strHumanverifyFieldName; }
        }
        public virtual string GetHumanverify()
        {
            return null;
        }
        #endregion

        #region Account
        public virtual taikhoan GetAccount()
        {
            return null;
        }
        #endregion

        #region Phone_Runtime
        private string _strPhone_RuntimeFieldName;

        public string Phone_RuntimeFieldName
        {
            get { return _strPhone_RuntimeFieldName; }
        }
        public virtual string GetPhoneRuntime()
        {
            return null;
        }
        #endregion

        #region Ma_bai_viet
        private string _strMaBaiViet;

        public string MaBaiViet
        {
            get { return _strMaBaiViet; }
        }
        public virtual string GetMaBaiViet()
        {
            return null;
        }
        #endregion

        #region Topic_Id
        private string _strTopicId;

        public string TopicId
        {
            get { return _strTopicId; }
        }
        public virtual string GetTopicId()
        {
            return null;
        }
        #endregion

    }
}
